/*
 * flash_driver.h
 * STM32F446 FLASH驱动程序头文件
 * 采用直接操作寄存器和LL库编写 
 */

#ifndef FLASH_DRIVER_H
#define FLASH_DRIVER_H

#include <stdint.h>

// STM32F446 FLASH寄存器定义
#define CUSTOM_FLASH_BASE            0x40023C00
#define FLASH_ACR             (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x00))  // 访问控制寄存器
#define FLASH_KEYR            (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x04))  // 密钥寄存器
#define FLASH_OPTKEYR         (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x08))  // 选项字节密钥寄存器
#define FLASH_SR              (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x0C))  // 状态寄存器
#define FLASH_CR              (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x10))  // 控制寄存器
#define FLASH_OPTCR           (*(volatile uint32_t *)(CUSTOM_FLASH_BASE + 0x14))  // 选项控制寄存器

// FLASH CR寄存器位定义（添加CUSTOM_前缀避免与CMSIS冲突）
#define CUSTOM_FLASH_CR_LOCK         (1U << 31)  // FLASH_CR寄存器中的LOCK位
#define CUSTOM_FLASH_CR_PER          (1U << 1)   // FLASH_CR寄存器中的PER位（扇区擦除）
#define CUSTOM_FLASH_CR_PG           (1U << 0)   // FLASH_CR寄存器中的PG位（编程）
#define CUSTOM_FLASH_CR_STRT         (1U << 16)  // FLASH_CR寄存器中的STRT位（开始擦除）
#define CUSTOM_FLASH_CR_SNB_MASK     (0x0F << 3) // FLASH_CR寄存器中的SNB位掩码（扇区号）

// FLASH SR寄存器位定义（添加CUSTOM_前缀避免与CMSIS冲突）
#define CUSTOM_FLASH_SR_BSY          (1U << 16)  // FLASH_SR寄存器中的BSY位（忙标志）
#define CUSTOM_FLASH_SR_PGSERR       (1U << 7)   // FLASH_SR寄存器中的PGSERR位（编程序列错误）
#define CUSTOM_FLASH_SR_PGPERR       (1U << 6)   // FLASH_SR寄存器中的PGPERR位（编程并行错误）
#define CUSTOM_FLASH_SR_PGAERR       (1U << 5)   // FLASH_SR寄存器中的PGAERR位（编程对齐错误）
#define CUSTOM_FLASH_SR_WRPERR       (1U << 4)   // FLASH_SR寄存器中的WRPERR位（写保护错误）
#define CUSTOM_FLASH_SR_OPERR        (1U << 1)   // FLASH_SR寄存器中的OPERR位（操作错误）

// FLASH密钥定义
#define FLASH_KEY1            0x45670123  // FLASH密钥1
#define FLASH_KEY2            0xCDEF89AB  // FLASH密钥2

// 系统时钟相关定义（假设180MHz系统时钟）
#ifndef DEFAULT_SYSTEM_CORE_CLOCK
#define DEFAULT_SYSTEM_CORE_CLOCK       180000000U  // 默认系统时钟频率
#endif

// 注意：在使用CMSIS的环境中，SystemCoreClock变量已由CMSIS库定义
// 此处不再重复定义，直接使用CMSIS提供的SystemCoreClock变量

// FLASH扇区定义（STM32F446系列）
#define FLASH_SECTOR_0      0      // 0x08000000 - 0x08003FFF (16KB)
#define FLASH_SECTOR_1      1      // 0x08004000 - 0x08007FFF (16KB)
#define FLASH_SECTOR_2      2      // 0x08008000 - 0x0800BFFF (16KB)
#define FLASH_SECTOR_3      3      // 0x0800C000 - 0x0800FFFF (16KB)
#define FLASH_SECTOR_4      4      // 0x08010000 - 0x0801FFFF (64KB)
#define FLASH_SECTOR_5      5      // 0x08020000 - 0x0803FFFF (128KB)
#define FLASH_SECTOR_6      6      // 0x08040000 - 0x0807FFFF (256KB)
#define FLASH_SECTOR_7      7      // 0x08080000 - 0x080BFFFF (256KB)

// FLASH基地址
#define FLASH_BASE_ADDR     0x08000000

// FLASH扇区大小（字节）
#define FLASH_SECTOR_0_1_2_3_SIZE   (16 * 1024)  // 16KB
#define FLASH_SECTOR_4_SIZE         (64 * 1024)  // 64KB
#define FLASH_SECTOR_5_SIZE         (128 * 1024) // 128KB
#define FLASH_SECTOR_6_7_SIZE       (256 * 1024) // 256KB

// FLASH状态定义
#define FLASH_OK            0       // 操作成功
#define FLASH_ERROR         1       // 操作失败（通用错误）
#define FLASH_BUSY          2       // FLASH当前忙碌，无法执行操作
#define FLASH_TIMEOUT       3       // 操作超时
#define FLASH_ADDR_ERROR    4       // 地址无效或超出范围
#define FLASH_LENGTH_ERROR  5       // 数据长度无效或跨扇区

// 定义所有错误标志的组合掩码，方便统一操作
#define CUSTOM_FLASH_ALL_ERRORS   (CUSTOM_FLASH_SR_OPERR | CUSTOM_FLASH_SR_WRPERR | \
                                   CUSTOM_FLASH_SR_PGAERR | CUSTOM_FLASH_SR_PGPERR | \
                                   CUSTOM_FLASH_SR_PGSERR)

// 注意：FLASH_SUCCESS已被FLASH_OK替代，保持向后兼容
#define FLASH_SUCCESS       FLASH_OK

/**
 * @brief 根据地址获取扇区号
 * @param address FLASH地址
 * @return 扇区号，如果地址无效返回FLASH_SECTOR_7 + 1（超出有效范围）
 */
extern uint32_t FLASH_GetSectorByAddress(uint32_t address);

/**
 * @brief 获取扇区大小
 * @param sector 扇区号
 * @return 扇区大小（字节）
 */
extern uint32_t FLASH_GetSectorSize(uint32_t sector);

/**
 * @brief 获取扇区起始地址
 * @param sector 扇区号
 * @return 扇区起始地址
 */
extern uint32_t FLASH_GetSectorStartAddress(uint32_t sector);

/**
 * @brief 检查地址是否在有效范围内
 * @param address 起始地址
 * @param length 数据长度
 * @return FLASH_OK或FLASH_ADDR_ERROR
 */
extern uint8_t FLASH_CheckAddressValid(uint32_t address, uint32_t length);

/**
 * @brief 检查是否在单个扇区内
 * @param address 起始地址
 * @param length 数据长度
 * @return FLASH_OK、FLASH_ADDR_ERROR或FLASH_LENGTH_ERROR
 */
extern uint8_t FLASH_CheckSingleSector(uint32_t address, uint32_t length);

/**
 * @brief 初始化FLASH
 * @note 根据系统时钟频率自动设置FLASH等待周期
 * @return FLASH_OK或FLASH_ERROR
 */
extern uint8_t FLASH_Init(void);

/**
 * @brief 擦除扇区
 * @param sector 要擦除的扇区号
 * @note 操作完成后会自动锁定FLASH
 * @return FLASH_OK、FLASH_ERROR或FLASH_TIMEOUT
 */
extern uint8_t FLASH_EraseSector(uint32_t sector);

/**
 * @brief 写入FLASH（只在单扇区内执行）
 * @param address 起始地址
 * @param data 要写入的数据
 * @param length 数据长度
 * @note 自动使用最高效的写入方式，优先32位写入，操作完成后会自动锁定FLASH
 * @return FLASH_OK、FLASH_ERROR、FLASH_ADDR_ERROR、FLASH_LENGTH_ERROR或FLASH_TIMEOUT
 */
extern uint8_t FLASH_Write(uint32_t address, uint8_t *data, uint32_t length);

/**
 * @brief 读取FLASH
 * @param address 起始地址
 * @param buffer 存储读取数据的缓冲区
 * @param length 要读取的数据长度
 * @note 自动使用最高效的读取方式，优先32位读取
 * @return FLASH_OK、FLASH_ERROR或FLASH_ADDR_ERROR
 */
extern uint8_t FLASH_Read(uint32_t address, uint8_t *buffer, uint32_t length);

/**
 * @brief 写入ADS1230数据到FLASH扇区5
 * @param zero_data ADS1230零位数据（int32_t类型）
 * @param calib_factor ADS1230校准因子（float类型）
 * @return FLASH_OK、FLASH_ERROR或FLASH_TIMEOUT
 * @note 数据从扇区5的起始地址开始写入
 */
extern uint8_t FLASH_WriteADS1230Data(int32_t zero_data, float calib_factor);

/**
 * @brief 从FLASH扇区5读取ADS1230数据
 * @param zero_data 用于存储零位数据的指针
 * @param calib_factor 用于存储校准因子的指针
 * @return FLASH_OK或FLASH_ERROR
 */
extern uint8_t FLASH_ReadADS1230Data(int32_t *zero_data, float *calib_factor);

/**
 * @brief 清除FLASH所有错误标志
 * @note 使用此函数可以统一清除所有可能的FLASH错误标志
 * @return 无
 */
extern void FLASH_ClearAllErrorFlags(void);

#endif /* FLASH_DRIVER_H */